﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Noris.Schedule.UI.Components;
using Noris.Schedule.UI.Expressions;
using Noris.Schedule.Support.Sql;
using Noris.Schedule.Support.Services;
using Noris.Schedule.Support;

namespace Noris.Schedule.UI
{
    public partial class EditExpressionForm : DForm
    {
		#region Konstrukce a vnitřní události
        public EditExpressionForm()
        {
            InitializeComponent();
            this.Init();
        }
        private void Init()
        {
            this.Records = new List<SchedulerConfigCls>();

            this._SaveBtn.Image = Noris.Schedule.Schedule.Pics.PicLibrary22.MediaFloppy35_FromFile;
            this._SaveAllBtn.Image = Noris.Schedule.Schedule.Pics.PicLibrary22.MediaFloppy35multi_FromFile;
            this._RevertBtn.Image = Noris.Schedule.Schedule.Pics.PicLibrary22.DocumentQuickRestart_FromFile;

            this._SelectShort.Tag = 3;
            this._SelectMedium.Tag = 4;
            this._SelectLong.Tag = 5;
            this._SelectTitle.Tag = 1;
            this._SelectTooltip.Tag = 2;
            this.CurrentToolTipText = "";

            this._Timer = new Timer() { Enabled = false };
            this._Timer.Tick += new EventHandler(_Timer_Tick);

            this.AutoSave = Steward.AppConfig.UserData.GetData(_DATA_AUTO_SAVE, false);
            this._AutoSave.Checked = this.AutoSave;
            this._CheckButtonSetVisualState(this._AutoSave);
            this._AutoSave.CheckedChanged += new EventHandler(_AutoSave_CheckedChanged);

            this.ParseImmediatelly = Steward.AppConfig.UserData.GetData(_DATA_PARSE_IMMEDIATELLY, false);
            this._ParseImmediatellyBtn.Checked = this.ParseImmediatelly;
            this._CheckButtonSetVisualState(this._ParseImmediatellyBtn);
            this._ParseImmediatellyBtn.CheckedChanged += new System.EventHandler(this._ParseImmediatellyBtn_CheckedChanged);

            this._EditPanel.EditedTextChanged += new EventHandler(_EditPanel_EditedTextChanged);
            this._EditPanel.VisualSettingChanged += new EventHandler(_EditPanel_VisualSettingChanged);
            this.Shown += new EventHandler(_Shown);
            this.FormClosing += new FormClosingEventHandler(_FormClosing);
        }

        void _Shown(object sender, EventArgs e)
        {
            if (this._ConfigurationKey == null)
                this._LoadDataForKey("sample");
        }
        private Timer _Timer;
		private void _SaveBtn_Click(object sender, EventArgs e)
		{
            this.StoreChangeToCurrentRecords();
			if (this.CurrentTextRecord != null)
				this.CurrentTextRecord.Save();
            this.RefreshStatusBarInfo();                         // Zobrazí počet změněných záznamů ve statusbaru
        }
		private void _SaveAllBtn_Click(object sender, EventArgs e)
		{
            this.StoreChangeToCurrentRecords();
			foreach (SchedulerConfigCls record in this.Records)
				record.Save();
            this.RefreshStatusBarInfo();                         // Zobrazí počet změněných záznamů ve statusbaru
        }
		private void _RevertBtn_Click(object sender, EventArgs e)
		{
            this.StoreChangeToCurrentRecords();
            if (this.CurrentTextRecord != null)
            {
                if (this.CurrentTextRecord.RecordNumber > 0)
                    this.CurrentTextRecord.Load(this.CurrentTextRecord.RecordNumber);
                else
                    this.CurrentTextRecord.Text = "";

                this.ShowTextFromCurrentRecord();
                this.EvaluateText(this.CurrentTextRecord);
            }
            this.RefreshStatusBarInfo();                         // Zobrazí počet změněných záznamů ve statusbaru
        }
		private void _SelectText_ItemClick(object sender, EventArgs e)
		{
            this.StoreChangeToCurrentRecords();
            ToolStripItem item = sender as ToolStripItem;
			if (item == null) return;
			object tag = item.Tag;
			if (tag is int)
				this.ShowTextFromRecordOfType((int)tag);
		}
        private void _AutoSave_CheckedChanged(object sender, EventArgs e)
        {
            this._CheckButtonSetVisualState(this._AutoSave);
            this.AutoSave = this._AutoSave.Checked;
            Steward.AppConfig.UserData.SetData(_DATA_AUTO_SAVE, this.AutoSave);
            if (this.AutoSave)
                this.AutoSaveCurrentRecord();
        }
        private void _ParseImmediatellyBtn_CheckedChanged(object sender, EventArgs e)
        {
            this._CheckButtonSetVisualState(this._ParseImmediatellyBtn);
            this.ParseImmediatelly = this._ParseImmediatellyBtn.Checked;
            Steward.AppConfig.UserData.SetData(_DATA_PARSE_IMMEDIATELLY, this.ParseImmediatelly);
            if (this.ParseImmediatelly)
                this.StoreChangeToCurrentRecords();
        }
        private void _CheckButtonSetVisualState(ToolStripButton button)
        {
            bool isChecked = button.Checked;
            button.BackColor = (isChecked ? SystemColors.Info : SystemColors.Control);
            button.Font = new Font(button.Font, (isChecked ? FontStyle.Bold : FontStyle.Regular));
        }
        private void _EditPanel_EditedTextChanged(object sender, EventArgs e)
		{
			if (!this._SuppressRtfEditorTextChanged)
			{
				this._SuppressRtfEditorTextChanged = true;
				this.StoreEditedTextToCurrentTextRecord(false);
				this._SuppressRtfEditorTextChanged = false;
			}
		}
        private void _EditPanel_VisualSettingChanged(object sender, EventArgs e)
        {
            this.StoreEditedTextToCurrentSettingRecord();
        }
        /// <summary>
        /// On Timer: pokud máme změny textu, uložíme je do záznamu.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _Timer_Tick(object sender, EventArgs e)
        {
            this._Timer.Enabled = false;
            this.StoreChangeToCurrentRecords();
        }
        private void _FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = !this.AutoSaveAllRecordsOnClose();
        }
        /// <summary>
		/// true potlačí event _RtfEditor_TextChanged
		/// </summary>
		private bool _SuppressRtfEditorTextChanged;
        private const string _DATA_AUTO_SAVE = "EditExpressionForm_AutoSave";
        private const string _DATA_PARSE_IMMEDIATELLY = "EditExpressionForm_ParseImmediatelly";
		#endregion
		#region Public property a eventy - Rozhraní na EditPanel
		/// <summary>
        /// Číslo třídy v rootu stromu
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int RootClassNumber
        {
            get { return this._EditPanel.RootClassNumber; }
            set { this._EditPanel.RootClassNumber = value; }
        }
        /// <summary>
        /// Objekt umožňující rozšiřovat strom tříd o další třídy, vztahy a atributy.
        /// Objekt je nutno setovat ještě před setováním RootClassNumber, 
        /// protože při vložení hodnoty do RootClassNumber se začínají načítat data pro tuto třídu,
        /// a v tu chvíli je třeba již mít přístup na ClassTreeExtender.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IClassTreeExtender ClassTreeExtender
        {
            get { return this._EditPanel.ClassTreeExtender; }
            set { this._EditPanel.ClassTreeExtender = value; }
        }
        /// <summary>
        /// Image na buttonu Select
        /// </summary>
        [Category("ExpressionEditor")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Description("Image na buttonu Select")]
        public Image ButtonImage
        {
            get { return this._EditPanel.ButtonImage; }
            set { this._EditPanel.ButtonImage = value; }
        }
        /// <summary>
        /// Text na buttonu Select
        /// </summary>
        [Category("ExpressionEditor")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        [Description("Text na buttonu Select")]
        public string ButtonText
        {
            get { return this._EditPanel.ButtonText; }
            set { this._EditPanel.ButtonText = value; }
        }
        /// <summary>
        /// Text (holý text, ne RTF) v editoru
        /// </summary>
        [Category("ExpressionEditor")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Description("Text (holý text, ne RTF) v editoru")]
        public string EditedText
        {
            get { return this._EditPanel.EditedText; }
            set { this._EditPanel.EditedText = value; }
        }
        /// <summary>
        /// Text ve formátu RTF v editoru
        /// </summary>
        [Category("ExpressionEditor")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Description("Text ve formátu RTF v editoru")]
        public string EditedTextRtf
        {
            get { return this._EditPanel.EditedTextRtf; }
            set { this._EditPanel.EditedTextRtf = value; }
        }
        /// <summary>
        /// Zoom v RTF editoru (lze jej nastavovat i kolečkem myši)
        /// </summary>
        [Category("ExpressionEditor")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Description("Text ve formátu RTF v editoru")]
        public float RtfZoomFactor
        {
            get { return this._EditPanel.RtfZoomFactor; }
            set { this._EditPanel.RtfZoomFactor = value; }
        }
        /// <summary>
        /// Viditelnost panelu pro nastavení fontu a dalších vlastností
        /// </summary>
        [Category("ExpressionEditor")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Description("Viditelnost panelu pro nastavení fontu a dalších vlastností")]
        public bool VisualSettingVisible
        {
            get { return this._EditPanel.VisualSettingVisible; }
            set { this._EditPanel.VisualSettingVisible = value; }
        }
        /// <summary>
        /// Aktuální serializovaná hodnota v panelu pro nastavení fontu a dalších vlastností
        /// </summary>
        [Category("ExpressionEditor")]
        [Browsable(true)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        [Description("Aktuální serializovaná hodnota v panelu pro nastavení fontu a dalších vlastností")]
        public string VisualSettingSerialized
        {
            get { return this._EditPanel.VisualSettingSerialized; }
            set { this._EditPanel.VisualSettingSerialized = value; }
        }
		/// <summary>
		/// Handler události Změna textu v editoru
		/// </summary>
		[Category("ExpressionEditor")]
		[Browsable(true)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[Description("Handler události Změna textu v editoru")]
		public event EventHandler EditedTextChanged;
		#endregion
        #region Práce se sadou dokumentů, Load, Save
        /// <summary>
        /// Klíč skupiny textů.
        /// Klíč deklaruje element ve své property IConfiguredText.ConfigurationKey, určuje konkrétní sadu konfigurací.
        /// <para>
        /// POZOR: vložení hodnoty klíče vede k zahození všech dosud načtených (a editovaných) dat a k načtení dat odpovídajících zadanému klíči.
        /// </para>
        /// <para>
        /// Klíč je uložen v databázi v lcs.scheduler_config.klic (varchar(40)).
        /// Další identifikátory v databázi jsou: 
        /// lcs.scheduler_config.skupina : pro konfigurované texty má hodnotu 1
        /// lcs.scheduler_config.typ : má hodnotu 1 = titulek tooltipu (zatím se nezadává), 2 = text tooltipu,  3-5 = texty elementu od nejkratšího po nejdelší
        /// </para>
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string ConfigurationKey
        {
            get { return this._ConfigurationKey; }
            set { this._LoadDataForKey(value); }
        }
        private string _ConfigurationKey;
        /// <summary>
        /// Volitelně zde může být uložen odkaz na objekt, pro který se texty editují.
        /// Pokud zde bude, bude se používat pro generování ukázek textů.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IConfiguredText SampleConfiguredText { get; set; }
        /// <summary>
        /// Odkaz na datový zdroj používaný pro evaluaci textu pro element this.SampleConfiguredText.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public IEvaluationDataSource CurrentDataSource { get; set; }
        /// <summary>
        /// Načte záznamy pro daný klíč textů.
        /// </summary>
        /// <param name="value"></param>
        private void _LoadDataForKey(string value)
        {
            this._ConfigurationKey = value;

            string sql = SchedulerConfigCls.SqlSelect + " WHERE skupina=1 and klic=" + Noris.Schedule.Support.Sql.SqlFormat.ToSql(value);
            this.Records = Noris.Schedule.Support.Sql.Db_Layer.GetList<SchedulerConfigCls>(sql);
            
            // Musíme zajistit přítomnost 6 základních záznamů:
            this.CreateRecordIfNotExists(1, delegate { return new SchedulerConfigCls(true) { Typ = Noris.Schedule.Support.Expressions.Constants.CONFIG_KLIC_TOOLTIP_TITLE, Skupina = Noris.Schedule.Support.Expressions.Constants.CONFIG_GROUP_TEXT, Klic = this._ConfigurationKey, Nazev = "Titulek ToolTipu" }; });
            this.CreateRecordIfNotExists(2, delegate { return new SchedulerConfigCls(true) { Typ = Noris.Schedule.Support.Expressions.Constants.CONFIG_KLIC_TOOLTIP_TEXT, Skupina = Noris.Schedule.Support.Expressions.Constants.CONFIG_GROUP_TEXT, Klic = this._ConfigurationKey, Nazev = "Text ToolTipu" }; });
            this.CreateRecordIfNotExists(3, delegate { return new SchedulerConfigCls(true) { Typ = Noris.Schedule.Support.Expressions.Constants.CONFIG_KLIC_CAPTION_SHORT, Skupina = Noris.Schedule.Support.Expressions.Constants.CONFIG_GROUP_TEXT, Klic = this._ConfigurationKey, Nazev = "Text elementu krátký" }; });
            this.CreateRecordIfNotExists(4, delegate { return new SchedulerConfigCls(true) { Typ = Noris.Schedule.Support.Expressions.Constants.CONFIG_KLIC_CAPTION_MEDIUM, Skupina = Noris.Schedule.Support.Expressions.Constants.CONFIG_GROUP_TEXT, Klic = this._ConfigurationKey, Nazev = "Text elementu střední" }; });
            this.CreateRecordIfNotExists(5, delegate { return new SchedulerConfigCls(true) { Typ = Noris.Schedule.Support.Expressions.Constants.CONFIG_KLIC_CAPTION_LONG, Skupina = Noris.Schedule.Support.Expressions.Constants.CONFIG_GROUP_TEXT, Klic = this._ConfigurationKey, Nazev = "Text elementu dlouhý" }; });
            this.CreateRecordIfNotExists(6, delegate { return new SchedulerConfigCls(true) { Typ = Noris.Schedule.Support.Expressions.Constants.CONFIG_KLIC_VISUAL_SETTING, Skupina = Noris.Schedule.Support.Expressions.Constants.CONFIG_GROUP_TEXT, Klic = this._ConfigurationKey, Nazev = "Vizuální vlastnosti" }; });

            this.ShowTextFromRecordOfType(2);                    // Rozsvítíme text 2: "Text ToolTipu"
            this.RefreshStatusBarInfo();                         // Zobrazí počet změněných záznamů ve statusbaru
            foreach (SchedulerConfigCls record in this.Records)  // Promítneme všechny vstupní texty do statusbaru:
                this.EvaluateText(record);
        }
        /// <summary>
        /// Zajistí, že v poli this.Records bude alespoň jeden záznam daného typu.
        /// Pokud tam není, pak jej pomocí dodaného creatoru vytvoří.
        /// </summary>
        /// <param name="typ"></param>
        /// <param name="creator"></param>
        protected void CreateRecordIfNotExists(int typ, Func<SchedulerConfigCls> creator)
        {
            if (this.Records.Any(cfg => (!cfg.Typ.IsNull && cfg.Typ.Value == typ))) return;        // Záznam daného typu už je načten.

            // Vytvoříme nový záznam:
            SchedulerConfigCls record = creator();

            // Zajistíme, že záznam se bude tvářit jako "nezměněný":
            record.ResetDirty();

            this.Records.Add(record);
        }
        /// <summary>
        /// Řeší ukládání rozepsaných dokumentů před zavřením okna.
        /// Vrací true = okno se může zavřít / false = nezavírat.
        /// </summary>
        /// <returns></returns>
        protected bool AutoSaveAllRecordsOnClose()
        {
            this.StoreChangeToCurrentRecords();
            if (this.AutoSave)
            {   // Automaticky ukládat:
                foreach (SchedulerConfigCls record in this.Records.Where(r => r.IsDirty))
                    record.Save();
                return true;
            }
            else
            {   // Určíme neuložené dokumenty:
                int count = 0;
                string names = "";
                foreach (SchedulerConfigCls record in this.Records.Where(r => r.IsDirty))
                {
                    count++;
                    names+= (names.Length == 0 ? "" : ", ") + record.Nazev;
                }
                if (count == 0) return true;

                DialogResult response = Noris.Schedule.Support.Core.Dialog.ShowQuestionYNS(@"V okně jsou některé texty, které nejsou uloženy:
" +  names + @".
Přejete si záznamy uložit?

ANO = uložit a zavřít okno
NE = neukládat, ztratit změny a zavřít okno
STORNO = data neukládat, nezavírat okno, pokračovat v editaci.");

                switch (response)
                {
                    case System.Windows.Forms.DialogResult.Yes:
                        foreach (SchedulerConfigCls record in this.Records.Where(r => r.IsDirty))
                            record.Save();
                        return true;
                        
                    case System.Windows.Forms.DialogResult.No:
                        return true;

                    case System.Windows.Forms.DialogResult.Cancel:
                        return false;
                }
                return true;
            }
        }
        /// <summary>
        /// Určí text do status baru do prvku _StatusInfo, a vypíše jej tam
        /// </summary>
        protected void RefreshStatusBarInfo()
        {
            if (this.InvokeRequired)
                this.BeginInvoke(new Action(this.RefreshStatusBarInfo));
            else
            {
                int dirtyCnt = this.Records.Count(r => r.IsDirty);
                string info = "Neuložených záznamů: " + dirtyCnt.ToString() + " (z " + this.Records.Count.ToString() + ")";
                this._StatusInfo.Text = info;
            }
        }
        /// <summary>
        /// Příznak true, pokud v tomto okně existuje nějaký záznam změněný a neuložený
        /// </summary>
        protected bool ContainDirtyRecord { get { return this.Records.Any(r => r.IsDirty); } }
        /// <summary>
        /// Seznam všech aktuálních záznamů = odpovídajících klíči this.ConfigurationKey
        /// </summary>
        protected List<SchedulerConfigCls> Records;
        #endregion
        #region Práce s jedním dokumentem, zpracování textu Show/Store
        /// <summary>
        /// Zobrazí data záznamu daného typu.
        /// A to jak v RTF editoru, tak v Toolbaru (název v DropDownu).
        /// Záznam zpřístupní = uloží jej do this.CurrentRecord
        /// </summary>
        /// <param name="typ"></param>
        protected void ShowTextFromRecordOfType(int typ)
        {
            this.StoreChangeToCurrentRecords();

            bool settingVisible = (typ == 3 || typ == 4 || typ == 5);
            if (!settingVisible && this.VisualSettingVisible)
                this.VisualSettingVisible = false;

            SchedulerConfigCls selectedRecord = this.Records.FirstOrDefault(cfg => (!cfg.Typ.IsNull && cfg.Typ.Value == typ));
            if (selectedRecord != null)
            {
                this.AutoSaveCurrentRecord();
                this.CurrentTextRecord = selectedRecord;
                this._SelectTextDdb.Text = this.CurrentTextRecord.Nazev;
                this.ShowTextFromCurrentRecord();
            }

            if (settingVisible && !this.VisualSettingVisible)
            {
                this._VisualSettingFind();
                this.VisualSettingVisible = true;
            }
        }

        private void _VisualSettingFind()
        {
            SchedulerConfigCls findSelectedRecord = this.Records.FirstOrDefault(cfg => (!cfg.Typ.IsNull && cfg.Typ.Value == 6));
            SchedulerConfigCls currSelectedRecord = this.CurrentVisualSettingRecord;
            int findKey = (findSelectedRecord == null ? 0 : findSelectedRecord.RecordNumber);
            int currKey = (currSelectedRecord == null ? 0 : currSelectedRecord.RecordNumber);
            bool isChange = (findKey != currKey);
            if (isChange)
            {
                this.CurrentVisualSettingRecord = findSelectedRecord;
                string serial = ((findSelectedRecord != null && !String.IsNullOrEmpty(findSelectedRecord.Text)) ? findSelectedRecord.Text : Noris.Schedule.Support.Expressions.ConfiguredSetting.Default);
                this.VisualSettingSerialized = serial;
            }
        }
        /// <summary>
        /// Provede Save pro CurrentRecord, pokud se to má a pokud je to zapotřebí.
        /// </summary>
        protected void AutoSaveCurrentRecord()
        {
            if (this.AutoSave && this.CurrentTextRecord != null && this.CurrentTextRecord.IsDirty)
            {
                this.CurrentTextRecord.Save();
                this.RefreshStatusBarInfo();                         // Zobrazí počet změněných záznamů ve statusbaru
            }
        }
        /// <summary>
        /// Zobrazí data aktuálního záznamu z this.CurrentRecord.Text do this.EditedText (Refresh pro směr Record =» Editor).
        /// Event po změně textu je potlačen.
        /// Neprovádí se vyhodnocení obsahu this.EvaluateText(this.CurrentRecord);
        /// </summary>
        protected void ShowTextFromCurrentRecord()
        {
            this._SuppressRtfEditorTextChanged = true;
            if (this.CurrentTextRecord != null)
            {
                this.EditedText = this.CurrentTextRecord.Text;
            }
            else
            {
                this.EditedText = "";
            }
            this._SuppressRtfEditorTextChanged = false;
        }
        /// <summary>
        /// Pokud v okně existují neuložené změny, pak je okamžitě uloží do aktuálního záznamu.
        /// </summary>
        protected void StoreChangeToCurrentRecords()
        {
            if (this.HasChangeForCurrentTextRecord)
                this.StoreEditedTextToCurrentTextRecord(true);
            this.StoreEditedTextToCurrentSettingRecord();
        }
        /// <summary>
        /// Uloží editovaný text z editoru do aktuálního záznamu.
        /// Tato metoda je volána vždy po provedení každé změny.
        /// Parametr immediately, pokud je true, požaduje okamžité bezpodmínečné uložení.
        /// Pokud je false, pak se pouze nastaví, že za nějaký čas bude vhodné text do záznamu vložit.
        /// </summary>
        protected void StoreEditedTextToCurrentTextRecord(bool immediately)
        {
            this._Timer.Enabled = false;
            if (immediately || this.ParseImmediatelly)
            {   // Okamžitě
                if (this.CurrentTextRecord != null)
                {
                    this.CurrentTextRecord.Text = this.EditedText;
                    this.RefreshStatusBarInfo();                         // Zobrazí počet změněných záznamů ve statusbaru
                    this.EvaluateText(this.CurrentTextRecord);
                }
                this.HasChangeForCurrentTextRecord = false;
            }
            else
            {   // Za chvíli:
                this._Timer.Interval = 2650;                // Text do záznamu opíšeme až po 2.65 sekundách, když mezitím uživatel neprovede další změnu (to by se nám interval zase vynuloval a budeme měřit další čas).
                this.HasChangeForCurrentTextRecord = true;
                this._Timer.Enabled = true;
            }
        }
        /// <summary>
        /// Uloží text setting z controlu do recordu
        /// </summary>
        protected void StoreEditedTextToCurrentSettingRecord()
        {
            if (this.VisualSettingVisible && this.CurrentVisualSettingRecord != null)
            {
                string currSerial = this.VisualSettingSerialized;
                string prevSerial = this.CurrentVisualSettingRecord.Text;
                bool isChange = !String.Equals(currSerial, prevSerial, StringComparison.InvariantCulture);
                if (isChange)
                {
                    this.CurrentVisualSettingRecord.Text = currSerial;
                    if (this.AutoSave)
                        this.CurrentVisualSettingRecord.Save();
                    this.RefreshStatusBarInfo();                         // Zobrazí počet změněných záznamů ve statusbaru
                }
            }
        }
        /// <summary>
        /// Aktuálně editovaný záznam s textem
        /// </summary>
        protected SchedulerConfigCls CurrentTextRecord;
        /// <summary>
        /// Aktuálně editovaný záznam s vizuálním nastavením
        /// </summary>
        protected SchedulerConfigCls CurrentVisualSettingRecord;
        /// <summary>
        /// Příznak, že RTF editor má nové změny, které nejsou uloženy do záznamu
        /// </summary>
        protected bool HasChangeForCurrentTextRecord;
        /// <summary>
        /// Příznak, že změny RTF se mají ukládat do záznamu a vyhodnocovat do statusbaru okamžitě, ne s časovým zpožděním.
        /// </summary>
        protected bool ParseImmediatelly;
        /// <summary>
        /// Příznak, že změny se mají ukládat do databáze automaticky.
        /// </summary>
        protected bool AutoSave;
        #endregion
        #region Vyhodnocování zadaného textu
        /// <summary>
        /// Vyhodnotí text vzorce z daného záznamu a promítne jej do odpovídajícího objektu statusbaru.
        /// </summary>
        /// <param name="record"></param>
        protected void EvaluateText(SchedulerConfigCls record)
        {
            if (record == null) return;
            string formula = record.Text;
            string sample = Noris.Schedule.Support.Expressions.Evaluator.GetText(this.SampleConfiguredText, this.CurrentDataSource, formula);

            int typ = (record.Typ.IsNull ? 0 : record.Typ.Value);
            switch (typ)
            {
                case 1: // Titulek ToolTipu
                    break;
                case 2: // Text ToolTipu
                    this.CurrentToolTipText = sample;
                    break;
                case 3: // Text elementu krátký
                    this._SampleText1.Text = sample;
                    break;
                case 4: // Text elementu střední
                    this._SampleText2.Text = sample;
                    break;
                case 5: // Text elementu dlouhý
                    this._SampleText3.Text = sample;
                    break;
            }

            // Znovu setovat ToolTipy:
            this._SampleText1.ToolTipText = this.CurrentToolTipText;
            this._SampleText2.ToolTipText = this.CurrentToolTipText;
            this._SampleText3.ToolTipText = this.CurrentToolTipText;
            this._StatusBar.ShowItemToolTips = true;
            this._SampleText1.AutoToolTip = true;
            this._SampleText2.AutoToolTip = true;
            this._SampleText3.AutoToolTip = true;

        }
        /// <summary>
        /// Zachycená hodnota vyhodnoceného textu ToolTipu pro StatusBar.
        /// Důvod: pokud pro položku StatusBar (například this._SampleText1) změním property Text, pak se ta hodnota přepíše i do property ToolTipText.
        /// Takže každé vyhodnocení ToolTipu se ukládá do CurrentToolTipText (tj. sem), a po každé změně Text se odsud aktualizuje TooTipText.
        /// Ach, ta inteligence WinForms...
        /// </summary>
        protected string CurrentToolTipText;
        #endregion
    }
}
